/*
 * Package il.ac.biu.cs.grossmm.impl.activeData
 * File MemEventInspector.java
 * 
 * This is a part of presence service framework prototype. 
 * See javadoc for more information.
 *  
 * Copyright (C) 2006 Grossmann Mark
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package il.ac.biu.cs.grossmm.impl.activeData;

import java.util.Set;

import il.ac.biu.cs.grossmm.api.OperationFailedException;
import il.ac.biu.cs.grossmm.api.data.*;
import il.ac.biu.cs.grossmm.api.flow.NodeEventInspector;

public class MemEventInspector extends MemInspector implements
		NodeEventInspector {

	public static final MemEventInspector INSTANCE = new MemEventInspector();

	public MemEventInspector() {
		super(0);
	}

	@SuppressWarnings("unchecked")
	public <N, V> V getOldValue(Node<N> node, Property<N, V> property) {
		MemNode n = (MemNode<N>) node;

		return (V) n.getValue(property, 0);
	}

	@SuppressWarnings("unchecked")
	public <N, S> Set<Node<S>> getSubnodes(Node<N> node, Nodeset<N, S> nodeSet,
			UpdateType u) {
		MemNode n = (MemNode<N>) node;

		return n.getSubnodes(nodeSet, u, 0);
	}

	private void toStringBuffer(Node node, StringBuffer sb, String prefix)
			throws OperationFailedException {
		NodeType type = node.getNodeType();

		int numOfProps = type.propertiesNumber();

		for (int i = 0; i < numOfProps; i++) {
			Property property = type.property(i);
			Object value = getValue(node, property);
			Object oldValue = getOldValue(node, property);
			sb.append(prefix);
			sb.append(property);
			sb.append(" = ");
			sb.append(value);
			if (!same(value, oldValue)) {
				sb.append(" <- ").append(oldValue);
			}
			sb.append("\n");
		}

		int numOfSets = type.nodesetsNumber();

		String prefix2 = prefix + "   ";

		for (int i = 0; i < numOfSets; i++) {
			Nodeset nodeset = type.nodeset(i);

			sb.append(prefix);
			sb.append(nodeset);
			sb.append(" = {\n");

			readSubnodes(sb, prefix2, node, nodeset, UpdateType.UNCHANGED);
			readSubnodes(sb, prefix2, node, nodeset, UpdateType.CHANGED);
			readSubnodes(sb, prefix2, node, nodeset, UpdateType.ADDED);
			readSubnodes(sb, prefix2, node, nodeset, UpdateType.REMOVED);

			sb.append(prefix).append("}\n");
		}
	}

	/**
	 * @param sb
	 * @param prefix2
	 * @param unchanged
	 * @param j
	 * @throws OperationFailedException
	 * @throws OperationFailedException
	 */
	private void readSubnodes(StringBuffer sb, String prefix2, Node node,
			Nodeset nodeset, UpdateType updateType)
			throws OperationFailedException {
		Set<Node> set = getSubnodes(node, nodeset, updateType);
		if (set.size() == 0)
			return;

		sb.append(prefix2).append("--").append(updateType).append("--").append(
				'\n');

		int j = 0;

		for (Node n : set) {
			if (j++ > 0)
				sb.append('\n');
			toStringBuffer(n, sb, prefix2);
		}
	}

	private boolean same(Object value, Object oldValue) {
		if (value == null)
			return oldValue == null;

		return value == oldValue || value.equals(oldValue);
	}

	public String toString(Node node) {
		StringBuffer sb = new StringBuffer("\n");
		try {
			toStringBuffer(node, sb, "");
		} catch (OperationFailedException e) {
			return "[[" + e.getMessage() + "]]";
		}

		return sb.toString();
	}
}
